#include <my_header.h>

typedef struct node_s{
    int num;
    struct node_s * next;
}node_t;

typedef struct queue_s{
    int node_size;
    node_t * front;
    node_t * tail;
}queue_t;

typedef struct share_value_s{
    queue_t queue;
    pthread_mutex_t mutex;
    pthread_cond_t cond_producer;
    pthread_cond_t cond_consumer;
}share_value_t;

void en_queue(queue_t *queue,int num);
void de_queue(queue_t *queue);
void print_queue(queue_t *queue);
void * thread_producer(void * arg);
void * thread_consumer(void * arg);
/* usage */
int main(int argc, char *argv[])
{
    ARGS_CHECK(argc,1);

    share_value_t share_value;
    memset(&share_value.queue,0,sizeof(queue_t));
    for(int i = 0;i < 8; i++)
    {
        int num = rand()%100;
        en_queue(&share_value.queue,num);
    }
    print_queue(&share_value.queue);
    printf("--------------------------------------\n");

    pthread_t tid[5];
    pthread_mutex_init(&share_value.mutex,NULL);
    pthread_cond_init(&share_value.cond_consumer,NULL);
    pthread_cond_init(&share_value.cond_producer,NULL);
    pthread_create(&tid[0],NULL,thread_producer,&share_value);
    pthread_create(&tid[1],NULL,thread_producer,&share_value);
    pthread_create(&tid[2],NULL,thread_producer,&share_value);
    pthread_create(&tid[3],NULL,thread_consumer,&share_value);
    pthread_create(&tid[4],NULL,thread_consumer,&share_value);

    for(int i = 0; i < 5; i++)
    {
        pthread_join(tid[0],NULL);
    }

    return 0;
}
//int main(int argc, char *argv[])
//{
//    ARGS_CHECK(argc,1);
//
//    queue_t queue;
//    memset(&queue,0,sizeof(queue_t));
//    for(int i = 0;i < 8; i++)
//    {
//        int num = rand()%100;
//        en_queue(&queue,num);
//    }
//    print_queue(&queue);
//
//    for(int i = 0;i<8;i++)
//    {
//        printf("queue size = %d de_queue name = %d\n",
//               queue.node_size,queue.front->num);
//        de_queue(&queue);
//        print_queue(&queue);
//    }
//    return 0;
//}

void en_queue(queue_t *queue,int num)
{
    node_t * new_node = (node_t *)calloc(1,sizeof(node_t));
    new_node->num = num;
    if(queue->node_size == 0)
    {
        queue->front = new_node;
        queue->tail = new_node;
    }
    else
    {
        queue->tail->next = new_node;
        queue->tail = new_node;
    }
    ++queue->node_size;
}
void de_queue(queue_t *queue)
{
    node_t * cur_node = queue->front;
    queue->front = cur_node->next;
    if(queue->node_size == 1)
    {
        queue->tail = NULL;
    }
    free(cur_node);
    --queue->node_size; 
}
void print_queue(queue_t *queue)
{
    node_t * cur_node = queue->front;
    while(cur_node)
    {
        printf("%4d",cur_node->num);
        cur_node = cur_node->next;
    }
    printf("\n");
}
void * thread_producer(void * arg)
{
    share_value_t *pshare_value = (share_value_t *)arg;
    while(1)
    {
        pthread_mutex_lock(&pshare_value->mutex);
        while(pshare_value->queue.node_size  >= 10)
        {
            printf("queue is full.\n");
            pthread_cond_wait(&pshare_value->cond_producer,&pshare_value->mutex);
        }
        int num = rand()%100;
        printf("produce name is %d\n",num);
        en_queue(&pshare_value->queue,num);
        print_queue(&pshare_value->queue);
        pthread_cond_signal(&pshare_value->cond_consumer);
        pthread_mutex_unlock(&pshare_value->mutex);

        sleep(3);
    }
    return NULL;
}
void * thread_consumer(void * arg)
{
    share_value_t *pshare_value = (share_value_t *)arg;
    sleep(5);
    while(1)
    {
        pthread_mutex_lock(&pshare_value->mutex);
        while(pshare_value->queue.node_size  <= 0)
        {
            printf("queue is empty.\n");
            pthread_cond_wait(&pshare_value->cond_consumer,&pshare_value->mutex);
        }
        int num = pshare_value->queue.front->num;
        de_queue(&pshare_value->queue);
        printf("consumer name is %d\n",num);
        print_queue(&pshare_value->queue);
        pthread_cond_signal(&pshare_value->cond_producer);
        pthread_mutex_unlock(&pshare_value->mutex);
        sleep(1);
    }
}
